/*
 * Copyright (c) 2008-2011, Petr Panteleyev
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *    3. The name of the author may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.panteleyev.blogclient;

import java.awt.FileDialog;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.EventObject;

import javax.swing.AbstractAction;
import javax.swing.JFileChooser;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;

import org.panteleyev.blogapi.IBlogEntry;
import org.panteleyev.blogclient.events.PostDeletedEvent;
import org.panteleyev.swing.BaseTable;
import org.panteleyev.swing.OSUtil;
import org.panteleyev.swing.TableUtil;
import org.panteleyev.utilities.Updatable;
import org.panteleyev.utilities.events.AppEventListener;

public abstract class BloggerHistoryFrame<T extends UserProfile<E>,E extends IBlogEntry> extends BloggerFrame<T> implements Updatable {

    protected abstract class ViewCommentsAction extends AbstractAction {
        public ViewCommentsAction() {
            super(L10N.HISTORY_FRANE_VIEW_COMMENTS_ACTION.s(), Icon.COMMENTS.i());
        }
    }

    private final ArrayList<E>          history = new ArrayList<>();

    private ArrayList<AbstractAction>   actions = new ArrayList<>();

    private AbstractAction              editEventAction;
    private AbstractAction              deleteEventAction;
    private AbstractAction              exportEventsAction;

    private final JTable                table = new BaseTable();
    private final JScrollPane           scroller = new JScrollPane(table);
    private AbstractTableModel          tableModel;

    public BloggerHistoryFrame(T profile) {
        super(profile);

        createActions();

        setTitle(L10N.HISTORY_WINDOW_TITLE.s());
        setIconImage(Icon.HISTORY.I().getImage());

        addAppEventListener(PostDeletedEvent.class, new AppEventListener() {
            @Override
            public void eventReceived(EventObject event) {
                onPostDeletedEvent((PostDeletedEvent)event);
            }
        });

        scroller.setPreferredSize(new java.awt.Dimension(50, 50));
        scroller.addComponentListener(new java.awt.event.ComponentAdapter() {
            @Override
            public void componentResized(java.awt.event.ComponentEvent evt) {
                TableUtil.adjustTableColumnSizes(getTable(), 2, scroller);
            }
        });

        table.addMouseListener(new java.awt.event.MouseAdapter() {
            @Override
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                if (evt.getClickCount() == 2) {
                    editEvent();
                }
            }
        });

        table.setShowGrid(false);
        scroller.getViewport().setBackground(table.getBackground());
    }

    protected JTable getTable() {
        return table;
    }

    public JScrollPane getScroller() {
        return scroller;
    }

    protected ArrayList<E> getHistory() {
        return history;
    }

    protected void setHistory(ArrayList<E> history) {
        this.history.clear();
        this.history.addAll(history);
    }

    protected AbstractTableModel getTableModel() {
        return tableModel;
    }

    protected void setTableModel(AbstractTableModel model) {
        tableModel = model;
        table.setModel(tableModel);
    }

    protected void createActions() {
        editEventAction = new AbstractAction(L10N.HISTORY_EDIT_EVENT_ACTION.s(), Icon.EDITDOC.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                editEvent();
            }
        };
        addAction(editEventAction);

        deleteEventAction = new AbstractAction(L10N.HISTORY_DELETE_EVENT_ACTION.s(), Icon.DELETE.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                deleteEvent();
            }
        };
        addAction(deleteEventAction);

        exportEventsAction = new AbstractAction(L10N.HISTORY_EXPORT_EVENTS_ACTION.s(), Icon.EMPTY.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                exportEvents();
            }
        };
        addAction(exportEventsAction);
    }

    protected String getTableDateColumnHeader() { return L10N.HISTORY_WINDOW_TABLE_DATE.s(); }
    protected String getTableSubjectColumnHeader() { return L10N.HISTORY_WINDOW_TABLE_SUBJECT.s(); }
    protected String getHistoryMenuName() { return L10N.HISTORY_WINDOW_TITLE.s(); }
    protected String getAfterCheckBoxLabel() { return L10N.HISTORY_FRAME_AFTER_CHECKBOX.s(); }
    protected String getBeforeCheckBoxLabel() { return L10N.HISTORY_FRAME_BEFORE_CHECKBOX.s(); }
    protected String getLastLabel() { return L10N.HISTORY_FRAME_LAST_LABEL.s(); }

    public AbstractAction getEditEventAction() {
        return editEventAction;
    }

    public AbstractAction getDeleteEventAction() {
        return deleteEventAction;
    }

    public AbstractAction getExportEventsAction() {
        return exportEventsAction;
    }

    public void addAction(AbstractAction a) {
        actions.add(a);
    }

    protected void enableActions(boolean enable) {
        for (AbstractAction a : actions) {
            a.setEnabled(enable);
        }
    }

    protected static String getExportEventsFileChooserApproveButtonText() {
        return L10N.HISTORY_EXPORT_EVENTS_DIALOG_TITLE.s();
    }

    private void onPostDeletedEvent(PostDeletedEvent event) {
        synchronized (history) {
            for (E entry : getHistory()) {
                if (entry.equals((E)event.getPost())) {
                    getHistory().remove(entry);
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            tableModel.fireTableDataChanged();
                        }
                    });
                    break;
                }
            }
        }
    }

    protected abstract void editEvent();
    protected abstract void deleteEvent();

    private void exportEvents() {
        final int[] rows = getTable().getSelectedRows();
        if (rows.length != 0) {
            File tmpDir = null;
            if (OSUtil.isMacOSX()) {
                System.setProperty("apple.awt.fileDialogForDirectories", "true");
                FileDialog d = new FileDialog(this, L10N.HISTORY_EXPORT_EVENTS_DIALOG_TITLE.s());
                d.setVisible(true);
                final String dName = d.getDirectory();
                final String fName = d.getFile();

                if (fName != null) {
                    StringBuilder b = new StringBuilder();
                    if (dName != null) {
                        b.append(dName);
                        b.append(File.separator);
                    }
                    b.append(fName);
                    tmpDir = new File(b.toString());
                }
            } else {
                JFileChooser d = new JFileChooser();
                d.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                d.setDialogTitle(L10N.HISTORY_EXPORT_EVENTS_DIALOG_TITLE.s());

                if (d.showDialog(this, getExportEventsFileChooserApproveButtonText()) == JFileChooser.APPROVE_OPTION) {
                    tmpDir = d.getSelectedFile();
                }
            }

            final File dir = tmpDir;

            if (dir != null && dir.exists()) {
                Thread thread = new Thread() {
                    @Override
                    public void run() {
                        SwingUtilities.invokeLater(new Runnable() {
                            @Override
                            public void run() {
                                enableActions(false);
                                getBusyLabel().setBusy(true);
                            }
                        });

                        for (int row : rows) {
                            E event = getHistory().get(row);
                            E expEvent = getFullEvent(event);

                            StringBuilder fName = new StringBuilder(expEvent.getId().toString());
                            fName.append(".pb");
                            File expFile = new File(dir, fName.toString());
                            try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(expFile))) {
                                out.writeObject(expEvent);
                            } catch (Exception ex) {
                                MainClass.handleException(BloggerHistoryFrame.this, ex);
                            }
                        }
                        SwingUtilities.invokeLater(new Runnable() {
                            @Override
                            public void run() {
                                getBusyLabel().setBusy(false);
                                enableActions(true);
                            }
                        });
                    }
                };

                thread.start();
            }
        }
    }

    protected E getFullEvent(E event) {
        return event;
    }
}
